﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace Asset
{
    public class Bundle : IAsyncBundle
    {
        protected Dictionary<string, IAsyncAsset> map = null;
        protected string resUrl;
        protected string resPath;
        public string URL => this.resUrl;
        protected AssetBundle assetBundle;
        public AssetBundle bundle => this.assetBundle;
        protected AsyncStatus asyncStatus = AsyncStatus.Waiting;
        public AsyncStatus Status => this.asyncStatus;

        protected List<IAsyncBundle> depends = null;
        protected int refCount = 0;
        public int RefCount { get => this.refCount; set => this.refCount = value; }
        public bool canUnload
        {
            get
            {
                return this.RefCount <= 0 && (this.map == null || this.map.Count <= 0);
            }
        }

        protected int costTimeMillSec = 0;
        public int loadCostTime => costTimeMillSec;

        public UnityEngine.Object editorAsset { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

#if UNITY_EDITOR
        protected double initTime = 0;
#endif

        public Bundle(string url)
        {
#if UNITY_EDITOR
            initTime = TimeUtils.nowTime;
#endif
            this.resUrl = url.ToLower();
            this.resPath = Path.Combine(Define.abPre, resUrl);
            initialize();
        }

        protected virtual void initialize()
        {
            string[] deps = PoolMgr.getDeps(this.URL);
            if (deps != null)
            {
                depends = new List<IAsyncBundle>();
                for (int i = 0; i < deps.Length; i++)
                {
                    IAsyncBundle depBundle = ResPool.Instance.getBundle(deps[i]);
                    if (depBundle == null)
                    {
                        depBundle = new Bundle(deps[i]);
                        ResPool.Instance.addBundle(depBundle);
                    }
                    depends.Add(depBundle);
                }
            }
            doLoadImm();
        }

        public virtual IEnumerator doLoad()
        {
            throw new NotImplementedException();
        }
        public virtual T loadAsset<T>(string resName) where T : UnityEngine.Object
        {
            Asset<T> asset = new Asset<T>(resName, this);
            return asset.Result;
        }

        public virtual AsyncAsset<T> loadAssetAsync<T>(string resName) where T : UnityEngine.Object
        {
            IAsyncAsset asyncAsset;
            if (map == null)
            {
                map = new Dictionary<string, IAsyncAsset>();
            }
            if (map.TryGetValue(resName, out asyncAsset))
            {
                AsyncAsset<T> asset = asyncAsset as AsyncAsset<T>;
                return asset;
            }
            else
            {
                AsyncAsset<T> asset = new AsyncAsset<T>(resName, this);
                map.Add(resName, asset);
                ResPool.Instance.addWaitingAsset(asset);
                return asset;
            }
        }

        public void doLoadImm()
        {
            if (this.Status != AsyncStatus.Finish)
            {
                this.assetBundle = AssetBundle.LoadFromFile(this.resPath);
#if UNITY_EDITOR
                this.costTimeMillSec = (int)(TimeUtils.nowTime - initTime);
#endif
                this.asyncStatus = AsyncStatus.Finish;
            }
        }

        public void removeAsyncAsset(string resName)
        {
            if (map != null)
            {
                map.Remove(resName);
            }
        }

        public void unload()
        {
            if (this.assetBundle != null)
            {
                this.assetBundle.Unload(true);
            }
        }
    }


}
